#pragma once
#include <vector>

#include "Constants.h"
#include "Cell.h"
using namespace std;

class Board {
public:
	class SideState {
	public:
		int mNestNum;
		int mEmptyNum;

		SideState();

		bool cantTurn();
		bool canPutOther();
		bool exsistOther();
		bool canExsistOther();
		bool isFull();
		int getWeight();
	};

	class State {

	public:
		static const int WON = 90000000;
	private:
		static const int IMMUTABLE_RATIO = 3;
		static const int POTEANTIAL_IMMUTABLE_RATIO = 1;
		static const int PUTTABLE_RATIO = 1;
		static const int POSITION_RATIO = 1;

		Board* mBoard;
		int mCountBlack;
		int mCountWhite;
		int mPositionBlack;
		int mPositionWhite;
		int mImmutableBlack;
		int mImmutableWhite;
		int mPotentialImmutableBlack;
		int mPotentialImmutableWhite;
		int mPutableCellsCount[2];

		int mPutablePoint;
		int mImmutablePoint;
		int mPotentialImmutablePoint;
		int mPositionPoint;
		int mPoint;

	private:
		int calcPutablePoint(int num);
		void calculate();
		void summary();
		void checkWeight(int x, int y);
		inline SideState checkSideWeight(int x, int y, int stepX, int stepY);
		bool checkLineImmutable(int color, int startX, int startY, int loop, int stepX, int stepY);
	public:
		State(Board* board);
		bool isCold();
		int getPutableCount(int color);
		int getImmutableCount(int color);
		int getPotentialImmutableCount(int color);
		int getPositionRawPoint(int color);
		int getPoint(int color);
		int getPutablePoint(int color);
		int getImmutablePoint(int color);
		int getPotentialImmutablePoint(int color);
		int getPositionPoint(int color);
		bool isWon(int color);
		bool isLoose(int color);
		bool isWideMarginWon(int color);
		bool isWideMarginPossibleWon(int color);
		bool isAdvantage(int color);
		string toString();
	};
private:
	int mTurnCount;
	int mStoneNum;
	Board::State* mState;
	vector<Cell*>* mPutableCellsCache[2];

	static const string LINE_TEXTS[];
	static const int POSITION_POINT[][BOARD_SIZE];
	static const int PUTABLE_MAP[];
protected:
	Cell*** mCells;
	bool mCompleted;
	friend class Game;
public:
	Board();
	Board(const Board& board);
	~Board();
	int getSize();
	int getTurnCount();
	int getStoneCount();
	Cell* getCell(int x, int y);
	bool isFull();
	vector<Cell*>* findPutableCells(int color);
	bool exisitsStone(int x, int y);
	string toString();
	void setStone(int x, int y, int color);
	void putStone(Cell* cell, int color);
	Board::State* getState();
	int getEmptyCellCount();
private:
	void init();
	inline bool canPut(int x, int y, int color);
	inline bool canPut(int x, int y, int stepX, int stepY, int color);
	inline void putStoneWithTurn(Cell* cell, int stepX, int stepY, int color);
	inline vector<Stone*> findTurnable(Cell* cell, int stepX, int stepY, int color);
	inline void checkLineImmutable(int color, Board board, int startX, int startY, int loop, int stepX, int stepY);
	inline bool isImmutable(int color, int x, int y);
	inline bool isRoundImmutable(int color, int x, int y);
	inline bool isImmutable(int x, int y);
	inline bool isRoundImmutable(int x, int y);

};
